package org.gap.jseed.injection;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.gap.jseed.Builder;
import org.gap.jseed.SeedContainer;
import org.gap.jseed.injection.annotation.Seed;

public class SeedInjector extends BaseInjector {
	private SeedContainer container;
	
	public void setSeedContainer(SeedContainer container) {
		this.container = container;
	}

	@Override
	protected Class<? extends Annotation> getAnnotationType() {
		return Seed.class;
	}

	@SuppressWarnings("unchecked")
	@Override
	protected void injectMethodWithCode(ClassWriter javaWriter, Method method, Annotation each) {
		if (method.getReturnType().equals(void.class)) {
			throw new IllegalStateException("Method must have a return type: " + javaWriter.getOriginalClass() + "." + method.getName());
		}
		container.bind(method.getReturnType(), new SeedFactory(method, container, javaWriter.getOriginalClass()));
	}

	@SuppressWarnings("rawtypes")
	public static class SeedFactory implements Builder {
		private final SeedContainer container;
		private final Class<?> lookup;
		private final Method method;

		public SeedFactory(Method method, SeedContainer container, Class<?> lookup) {
			this.container = container;
			this.lookup = lookup;
			this.method = method;
		}

		@Override
		public Class<?> getType() {
			return method.getReturnType();
		}

		@Override
		public Object createInstance() {
			Object object = container.get(lookup);
			List<Object> parameters = new ArrayList<Object>();
			for (Class<?> each : method.getParameterTypes()) {
				if (!container.hasService(each)) {
					throw new IllegalStateException("@Seed method is missing parameter for " + each.getName() + " with method " + lookup.getName() + "." + method.getName());
				}
				parameters.add(container.get(each));
			}
			try {
				return method.invoke(object, parameters.toArray());
			} catch (Exception e) {
				throw new IllegalStateException("@Seed method failed: " + lookup.getName() + "." + method.getName());
			}
		}

	}
}
